<template>
	<div
		class="el-slider__button-wrapper"
		@mouseenter="handleMouseEnter"
		@mouseleave="handleMouseLeave"
		@mousedown="onButtonDown"
		@touchstart="onButtonDown"
		:class="{ hover: hovering, dragging: dragging }"
		:style="wrapperStyle"
		ref="button"
		tabindex="0"
		@focus="handleMouseEnter"
		@blur="handleMouseLeave"
		@keydown.left="onLeftKeyDown"
		@keydown.right="onRightKeyDown"
		@keydown.down.prevent="onLeftKeyDown"
		@keydown.up.prevent="onRightKeyDown"
	>
		<el-tooltip placement="top" ref="tooltip" :popper-class="tooltipClass" :disabled="!showTooltip">
			<span slot="content">{{ formatValue }}</span>
			<div class="" :class="{ hover: hovering, dragging: dragging, actual: actual, target: target }"></div>
		</el-tooltip>
	</div>
</template>

<script>
// import ElTooltip from 'element-ui/packages/tooltip';

export default {
	name: 'ElSliderButton',

	components: {
		// ElTooltip
	},

	props: {
		value: {
			type: Number,
			default: 0
		},
		vertical: {
			type: Boolean,
			default: false
		},
		actual: {
			type: Boolean,
			default: false
		},
		target: {
			type: Boolean,
			default: false
		},
		tooltipClass: String
	},

	data() {
		return {
			hovering: false,
			dragging: false,
			isClick: false,
			startX: 0,
			currentX: 0,
			startY: 0,
			currentY: 0,
			startPosition: 0,
			newPosition: null,
			oldValue: this.value
		};
	},

	computed: {
		disabled() {
			return this.$parent.sliderDisabled;
		},

		max() {
			return this.$parent.max;
		},

		min() {
			return this.$parent.min;
		},

		step() {
			return this.$parent.step;
		},

		showTooltip() {
			return this.$parent.showTooltip;
		},

		precision() {
			return this.$parent.precision;
		},

		currentPosition() {
			return `${((this.value - this.min) / (this.max - this.min)) * 100}%`;
		},

		enableFormat() {
			return this.$parent.formatTooltip instanceof Function;
		},

		formatValue() {
			var title;
			this.actual ? (title = '实际进度:') : (title = '预计进度:');
			let value = (this.enableFormat && this.$parent.formatTooltip(this.value)) || this.value;
			return title + value;
		},

		wrapperStyle() {
			return this.vertical ? { bottom: this.currentPosition } : { left: this.currentPosition };
		}
	},

	watch: {
		dragging(val) {
			this.$parent.dragging = val;
		}
	},

	methods: {
		displayTooltip() {
			this.$refs.tooltip && (this.$refs.tooltip.showPopper = true);
		},

		hideTooltip() {
			this.$refs.tooltip && (this.$refs.tooltip.showPopper = false);
		},

		handleMouseEnter() {
			this.hovering = true;
			this.displayTooltip();
		},

		handleMouseLeave() {
			this.hovering = false;
			this.hideTooltip();
		},

		onButtonDown(event) {
			if (this.disabled) return;
			event.preventDefault();
			this.onDragStart(event);
			window.addEventListener('mousemove', this.onDragging);
			window.addEventListener('touchmove', this.onDragging);
			window.addEventListener('mouseup', this.onDragEnd);
			window.addEventListener('touchend', this.onDragEnd);
			window.addEventListener('contextmenu', this.onDragEnd);
		},
		onLeftKeyDown() {
			if (this.disabled) return;
			this.newPosition = parseFloat(this.currentPosition) - (this.step / (this.max - this.min)) * 100;
			this.setPosition(this.newPosition);
			this.$parent.emitChange();
		},
		onRightKeyDown() {
			if (this.disabled) return;
			this.newPosition = parseFloat(this.currentPosition) + (this.step / (this.max - this.min)) * 100;
			this.setPosition(this.newPosition);
			this.$parent.emitChange();
		},
		onDragStart(event) {
			this.dragging = true;
			this.isClick = true;
			if (event.type === 'touchstart') {
				event.clientY = event.touches[0].clientY;
				event.clientX = event.touches[0].clientX;
			}
			if (this.vertical) {
				this.startY = event.clientY;
			} else {
				this.startX = event.clientX;
			}
			this.startPosition = parseFloat(this.currentPosition);
			this.newPosition = this.startPosition;
		},

		onDragging(event) {
			if (this.dragging) {
				this.isClick = false;
				this.displayTooltip();
				this.$parent.resetSize();
				let diff = 0;
				if (event.type === 'touchmove') {
					event.clientY = event.touches[0].clientY;
					event.clientX = event.touches[0].clientX;
				}
				if (this.vertical) {
					this.currentY = event.clientY;
					diff = ((this.startY - this.currentY) / this.$parent.sliderSize) * 100;
				} else {
					this.currentX = event.clientX;
					diff = ((this.currentX - this.startX) / this.$parent.sliderSize) * 100;
				}
				this.newPosition = this.startPosition + diff;
				this.setPosition(this.newPosition);
			}
		},

		onDragEnd() {
			if (this.dragging) {
				/*
				 * 防止在 mouseup 后立即触发 click，导致滑块有几率产生一小段位移
				 * 不使用 preventDefault 是因为 mouseup 和 click 没有注册在同一个 DOM 上
				 */
				setTimeout(() => {
					this.dragging = false;
					this.hideTooltip();
					if (!this.isClick) {
						this.setPosition(this.newPosition);
						this.$parent.emitChange();
					}
				}, 0);
				window.removeEventListener('mousemove', this.onDragging);
				window.removeEventListener('touchmove', this.onDragging);
				window.removeEventListener('mouseup', this.onDragEnd);
				window.removeEventListener('touchend', this.onDragEnd);
				window.removeEventListener('contextmenu', this.onDragEnd);
			}
		},

		setPosition(newPosition) {
			if (newPosition === null || isNaN(newPosition)) return;
			if (newPosition < 0) {
				newPosition = 0;
			} else if (newPosition > 100) {
				newPosition = 100;
			}
			const lengthPerStep = 100 / ((this.max - this.min) / this.step);
			const steps = Math.round(newPosition / lengthPerStep);
			let value = steps * lengthPerStep * (this.max - this.min) * 0.01 + this.min;
			value = parseFloat(value.toFixed(this.precision));
			this.$emit('input', value);
			this.$nextTick(() => {
				this.displayTooltip();
				this.$refs.tooltip && this.$refs.tooltip.updatePopper();
			});
			if (!this.dragging && this.value !== this.oldValue) {
				this.oldValue = this.value;
			}
		}
	}
};
</script>

<style scoped="scoped">
.actual {
	border-left: 7px solid transparent;
	border-right: 7px solid transparent;
	border-bottom: 15px solid var(--custom-green);
	margin-top: 17px;
	/* border: 0px solid --custom-green; */
	background-color: transparent;
	border-radius: 0;
}
.target {
	width: 0;
	height: 0;
	border-right: 7px solid transparent;
	border-left: 7px solid transparent;
	border-top: 15px solid #409eff;
	margin-bottom: 15px;
}
</style>
